package org.xx.armory.commons;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * 用于初始化{@code Map}对象的构造器。
 *
 * @param <K>
 *         {@code Map}对象的键类型
 * @param <V>
 *         {@code Map}对象的值类型
 * @author Haart
 */
public class MapBuilder<K, V> {
    private final List<Entry<K, V>> entries;

    /**
     * 构造{@code MapBuilder}对象。
     */
    public MapBuilder() {
        this.entries = new ArrayList<>();
    }

    /**
     * 把映射列表逐个添加到{@code java.util.Map}对象中
     *
     * @param src
     *         映射列表。
     * @param dst
     *         目标{@code java.util.Map}对象。
     */
    private static <K, V> void fillMap(
            final List<Entry<K, V>> src,
            final Map<K, V> dst
    ) {
        for (final Entry<K, V> entry : src) {
            dst.put(entry.getKey(), entry.getValue());
        }
    }

    /**
     * 添加一个映射。
     *
     * @param key
     *         映射的键。
     * @param value
     *         映射的值。
     * @return {@code MapBuilder}对象本身。
     */
    public MapBuilder<K, V> put(
            K key,
            V value
    ) {
        this.entries.add(new Entry<>(key, value));
        return this;
    }

    /**
     * 根据之前添加的映射构造一个{@code java.util.HashMap}对象。
     *
     * <p>
     * 这些映射按照{@code put}方法被调用的顺序被添加到{@code java.util.HashMap}对象中。
     * </p>
     *
     * @return {@code java.util.HashMap}对象，此对象包含之前通过{@code put}方法添加的所有映射。
     * @see #put(Object, Object)
     */
    public HashMap<K, V> buildHashMap() {
        final HashMap<K, V> ret = new HashMap<>();

        fillMap(this.entries, ret);

        return ret;
    }

    /**
     * 根据之前添加的映射构造一个{@code java.util.LinkedHashMap}对象。
     *
     * <p>
     * 这些映射按照{@code put}方法被调用的顺序被添加到{@code java.util.LinkedHashMap}对象中。
     * </p>
     *
     * @return {@code java.util.LinkedHashMap}对象，此对象包含之前通过{@code put}方法添加的所有映射。
     * @see #put(Object, Object)
     */
    public LinkedHashMap<K, V> buildLinkedHashMap() {
        final LinkedHashMap<K, V> ret = new LinkedHashMap<>();

        fillMap(this.entries, ret);

        return ret;
    }

    /**
     * 根据之前添加的映射构造一个{@code java.util.TreeMap}对象。
     *
     * <p>
     * 这些映射按照{@code put}方法被调用的顺序被添加到{@code java.util.TreeMap}对象中。
     * </p>
     *
     * @return {@code java.util.TreeMap}对象，此对象包含之前通过{@code put}方法添加的所有映射。
     * @see #put(Object, Object)
     */
    public TreeMap<K, V> buildTreeMap() {
        return buildTreeMap(null);
    }

    /**
     * 根据之前添加的映射和指定的键比较器构造一个{@code java.util.TreeMap}对象。
     *
     * <p>
     * 这些映射按照{@code put}方法被调用的顺序被添加到{@code java.util.TreeMap}对象中。
     * </p>
     *
     * @param comparator
     *         用于构造{@code java.util.TreeMap}对象的键比较器。
     * @return {@code java.util.TreeMap}对象，此对象包含之前通过{@code put}方法添加的所有映射。
     * @see #put(Object, Object)
     * @see java.util.TreeMap#TreeMap(Comparator)
     */
    public TreeMap<K, V> buildTreeMap(final Comparator<? super K> comparator) {
        final TreeMap<K, V> ret = new TreeMap<>(comparator);

        fillMap(this.entries, ret);

        return ret;
    }

    private static class Entry<K, V> {
        private final K key;
        private final V value;

        public Entry(
                K key,
                V value
        ) {
            this.key = key;
            this.value = value;
        }

        public K getKey() {
            return this.key;
        }

        public V getValue() {
            return this.value;
        }
    }
}
